1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package scouter.javassist;
18
19 import java.io.BufferedInputStream;
20 import java.io.ByteArrayInputStream;
21 import java.io.ByteArrayOutputStream;
22 import java.io.DataInputStream;
23 import java.io.DataOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.lang.ref.WeakReference;
27 import java.net.URL;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.Hashtable;
31 import java.util.List;
32 import java.util.Set;
33
34 import scouter.javassist.CannotCompileException;
35 import scouter.javassist.ClassMap;
36 import scouter.javassist.ClassPool;
37 import scouter.javassist.CodeConverter;
38 import scouter.javassist.CtBehavior;
39 import scouter.javassist.CtClass;
40 import scouter.javassist.CtConstructor;
41 import scouter.javassist.CtField;
42 import scouter.javassist.CtMember;
43 import scouter.javassist.CtMethod;
44 import scouter.javassist.Modifier;
45 import scouter.javassist.NotFoundException;
46 import scouter.javassist.bytecode.AccessFlag;
47 import scouter.javassist.bytecode.AnnotationsAttribute;
48 import scouter.javassist.bytecode.AttributeInfo;
49 import scouter.javassist.bytecode.BadBytecode;
50 import scouter.javassist.bytecode.Bytecode;
51 import scouter.javassist.bytecode.ClassFile;
52 import scouter.javassist.bytecode.CodeAttribute;
53 import scouter.javassist.bytecode.CodeIterator;
54 import scouter.javassist.bytecode.ConstPool;
55 import scouter.javassist.bytecode.ConstantAttribute;
56 import scouter.javassist.bytecode.Descriptor;
57 import scouter.javassist.bytecode.EnclosingMethodAttribute;
58 import scouter.javassist.bytecode.FieldInfo;
59 import scouter.javassist.bytecode.InnerClassesAttribute;
60 import scouter.javassist.bytecode.MethodInfo;
61 import scouter.javassist.bytecode.ParameterAnnotationsAttribute;
62 import scouter.javassist.bytecode.SignatureAttribute;
63 import scouter.javassist.bytecode.annotation.Annotation;
64 import scouter.javassist.compiler.AccessorMaker;
65 import scouter.javassist.compiler.CompileError;
66 import scouter.javassist.compiler.Javac;
67 import scouter.javassist.expr.ExprEditor;
68
69
70
71
72
73 class CtClassType extends CtClass {
74 ClassPool classPool;
75 boolean wasChanged;
76 private boolean wasFrozen;
77 boolean wasPruned;
78 boolean gcConstPool;
79 ClassFile classfile;
80 byte[] rawClassfile;
81
82 private WeakReference memberCache;
83 private AccessorMaker accessors;
84
85 private FieldInitLink fieldInitializers;
86 private Hashtable hiddenMethods;
87 private int uniqueNumberSeed;
88
89 private boolean doPruning = ClassPool.doPruning;
90 private int getCount;
91 private static final int GET_THRESHOLD = 2;
92
93 CtClassType(String name, ClassPool cp) {
94 super(name);
95 classPool = cp;
96 wasChanged = wasFrozen = wasPruned = gcConstPool = false;
97 classfile = null;
98 rawClassfile = null;
99 memberCache = null;
100 accessors = null;
101 fieldInitializers = null;
102 hiddenMethods = null;
103 uniqueNumberSeed = 0;
104 getCount = 0;
105 }
106
107 CtClassType(InputStream ins, ClassPool cp) throws IOException {
108 this((String)null, cp);
109 classfile = new ClassFile(new DataInputStream(ins));
110 qualifiedName = classfile.getName();
111 }
112
113 CtClassType(ClassFile cf, ClassPool cp) {
114 this((String)null, cp);
115 classfile = cf;
116 qualifiedName = classfile.getName();
117 }
118
119 protected void extendToString(StringBuffer buffer) {
120 if (wasChanged)
121 buffer.append("changed ");
122
123 if (wasFrozen)
124 buffer.append("frozen ");
125
126 if (wasPruned)
127 buffer.append("pruned ");
128
129 buffer.append(Modifier.toString(getModifiers()));
130 buffer.append(" class ");
131 buffer.append(getName());
132
133 try {
134 CtClass ext = getSuperclass();
135 if (ext != null) {
136 String name = ext.getName();
137 if (!name.equals("java.lang.Object"))
138 buffer.append(" extends " + ext.getName());
139 }
140 }
141 catch (NotFoundException e) {
142 buffer.append(" extends ??");
143 }
144
145 try {
146 CtClass[] intf = getInterfaces();
147 if (intf.length > 0)
148 buffer.append(" implements ");
149
150 for (int i = 0; i < intf.length; ++i) {
151 buffer.append(intf[i].getName());
152 buffer.append(", ");
153 }
154 }
155 catch (NotFoundException e) {
156 buffer.append(" extends ??");
157 }
158
159 CtMember.Cache memCache = getMembers();
160 exToString(buffer, " fields=",
161 memCache.fieldHead(), memCache.lastField());
162 exToString(buffer, " constructors=",
163 memCache.consHead(), memCache.lastCons());
164 exToString(buffer, " methods=",
165 memCache.methodHead(), memCache.lastMethod());
166 }
167
168 private void exToString(StringBuffer buffer, String msg,
169 CtMember head, CtMember tail) {
170 buffer.append(msg);
171 while (head != tail) {
172 head = head.next();
173 buffer.append(head);
174 buffer.append(", ");
175 }
176 }
177
178 public AccessorMaker getAccessorMaker() {
179 if (accessors == null)
180 accessors = new AccessorMaker(this);
181
182 return accessors;
183 }
184
185 public ClassFile getClassFile2() {
186 ClassFile cfile = classfile;
187 if (cfile != null)
188 return cfile;
189
190 classPool.compress();
191 if (rawClassfile != null) {
192 try {
193 classfile = new ClassFile(new DataInputStream(
194 new ByteArrayInputStream(rawClassfile)));
195 rawClassfile = null;
196 getCount = GET_THRESHOLD;
197 return classfile;
198 }
199 catch (IOException e) {
200 throw new RuntimeException(e.toString(), e);
201 }
202 }
203
204 InputStream fin = null;
205 try {
206 fin = classPool.openClassfile(getName());
207 if (fin == null)
208 throw new NotFoundException(getName());
209
210 fin = new BufferedInputStream(fin);
211 ClassFile cf = new ClassFile(new DataInputStream(fin));
212 if (!cf.getName().equals(qualifiedName))
213 throw new RuntimeException("cannot find " + qualifiedName + ": "
214 + cf.getName() + " found in "
215 + qualifiedName.replace('.', '/') + ".class");
216
217 classfile = cf;
218 return cf;
219 }
220 catch (NotFoundException e) {
221 throw new RuntimeException(e.toString(), e);
222 }
223 catch (IOException e) {
224 throw new RuntimeException(e.toString(), e);
225 }
226 finally {
227 if (fin != null)
228 try {
229 fin.close();
230 }
231 catch (IOException e) {}
232 }
233 }
234
235
236
237
238
239
240 final void incGetCounter() { ++getCount; }
241
242
243
244
245
246
247 void compress() {
248 if (getCount < GET_THRESHOLD)
249 if (!isModified() && ClassPool.releaseUnmodifiedClassFile)
250 removeClassFile();
251 else if (isFrozen() && !wasPruned)
252 saveClassFile();
253
254 getCount = 0;
255 }
256
257
258
259
260
261 private synchronized void saveClassFile() {
262
263
264 if (classfile == null || hasMemberCache() != null)
265 return;
266
267 ByteArrayOutputStream barray = new ByteArrayOutputStream();
268 DataOutputStream out = new DataOutputStream(barray);
269 try {
270 classfile.write(out);
271 barray.close();
272 rawClassfile = barray.toByteArray();
273 classfile = null;
274 }
275 catch (IOException e) {}
276 }
277
278 private synchronized void removeClassFile() {
279 if (classfile != null && !isModified() && hasMemberCache() == null)
280 classfile = null;
281 }
282
283 public ClassPool getClassPool() { return classPool; }
284
285 void setClassPool(ClassPool cp) { classPool = cp; }
286
287 public URL getURL() throws NotFoundException {
288 URL url = classPool.find(getName());
289 if (url == null)
290 throw new NotFoundException(getName());
291 else
292 return url;
293 }
294
295 public boolean isModified() { return wasChanged; }
296
297 public boolean isFrozen() { return wasFrozen; }
298
299 public void freeze() { wasFrozen = true; }
300
301 void checkModify() throws RuntimeException {
302 if (isFrozen()) {
303 String msg = getName() + " class is frozen";
304 if (wasPruned)
305 msg += " and pruned";
306
307 throw new RuntimeException(msg);
308 }
309
310 wasChanged = true;
311 }
312
313 public void defrost() {
314 checkPruned("defrost");
315 wasFrozen = false;
316 }
317
318 public boolean subtypeOf(CtClass clazz) throws NotFoundException {
319 int i;
320 String cname = clazz.getName();
321 if (this == clazz || getName().equals(cname))
322 return true;
323
324 ClassFile file = getClassFile2();
325 String supername = file.getSuperclass();
326 if (supername != null && supername.equals(cname))
327 return true;
328
329 String[] ifs = file.getInterfaces();
330 int num = ifs.length;
331 for (i = 0; i < num; ++i)
332 if (ifs[i].equals(cname))
333 return true;
334
335 if (supername != null && classPool.get(supername).subtypeOf(clazz))
336 return true;
337
338 for (i = 0; i < num; ++i)
339 if (classPool.get(ifs[i]).subtypeOf(clazz))
340 return true;
341
342 return false;
343 }
344
345 public void setName(String name) throws RuntimeException {
346 String oldname = getName();
347 if (name.equals(oldname))
348 return;
349
350
351 classPool.checkNotFrozen(name);
352 ClassFile cf = getClassFile2();
353 super.setName(name);
354 cf.setName(name);
355 nameReplaced();
356 classPool.classNameChanged(oldname, this);
357 }
358
359 public String getGenericSignature() {
360 SignatureAttribute sa
361 = (SignatureAttribute)getClassFile2().getAttribute(SignatureAttribute.tag);
362 return sa == null ? null : sa.getSignature();
363 }
364
365 public void setGenericSignature(String sig) {
366 ClassFile cf = getClassFile();
367 SignatureAttribute sa = new SignatureAttribute(cf.getConstPool(), sig);
368 cf.addAttribute(sa);
369 }
370
371 public void replaceClassName(ClassMap classnames)
372 throws RuntimeException
373 {
374 String oldClassName = getName();
375 String newClassName
376 = (String)classnames.get(Descriptor.toJvmName(oldClassName));
377 if (newClassName != null) {
378 newClassName = Descriptor.toJavaName(newClassName);
379
380 classPool.checkNotFrozen(newClassName);
381 }
382
383 super.replaceClassName(classnames);
384 ClassFile cf = getClassFile2();
385 cf.renameClass(classnames);
386 nameReplaced();
387
388 if (newClassName != null) {
389 super.setName(newClassName);
390 classPool.classNameChanged(oldClassName, this);
391 }
392 }
393
394 public void replaceClassName(String oldname, String newname)
395 throws RuntimeException
396 {
397 String thisname = getName();
398 if (thisname.equals(oldname))
399 setName(newname);
400 else {
401 super.replaceClassName(oldname, newname);
402 getClassFile2().renameClass(oldname, newname);
403 nameReplaced();
404 }
405 }
406
407 public boolean isInterface() {
408 return Modifier.isInterface(getModifiers());
409 }
410
411 public boolean isAnnotation() {
412 return Modifier.isAnnotation(getModifiers());
413 }
414
415 public boolean isEnum() {
416 return Modifier.isEnum(getModifiers());
417 }
418
419 public int getModifiers() {
420 ClassFile cf = getClassFile2();
421 int acc = cf.getAccessFlags();
422 acc = AccessFlag.clear(acc, AccessFlag.SUPER);
423 int inner = cf.getInnerAccessFlags();
424 if (inner != -1 && (inner & AccessFlag.STATIC) != 0)
425 acc |= AccessFlag.STATIC;
426
427 return AccessFlag.toModifier(acc);
428 }
429
430 public CtClass[] getNestedClasses() throws NotFoundException {
431 ClassFile cf = getClassFile2();
432 InnerClassesAttribute ica
433 = (InnerClassesAttribute)cf.getAttribute(InnerClassesAttribute.tag);
434 if (ica == null)
435 return new CtClass[0];
436
437 String thisName = cf.getName() + "$";
438 int n = ica.tableLength();
439 ArrayList list = new ArrayList(n);
440 for (int i = 0; i < n; i++) {
441 String name = ica.innerClass(i);
442 if (name != null)
443 if (name.startsWith(thisName)) {
444
445 if (name.lastIndexOf('$') < thisName.length())
446 list.add(classPool.get(name));
447 }
448 }
449
450 return (CtClass[])list.toArray(new CtClass[list.size()]);
451 }
452
453 public void setModifiers(int mod) {
454 ClassFile cf = getClassFile2();
455 if (Modifier.isStatic(mod)) {
456 int flags = cf.getInnerAccessFlags();
457 if (flags != -1 && (flags & AccessFlag.STATIC) != 0)
458 mod = mod & ~Modifier.STATIC;
459 else
460 throw new RuntimeException("cannot change " + getName() + " into a static class");
461 }
462
463 checkModify();
464 cf.setAccessFlags(AccessFlag.of(mod));
465 }
466
467
468 public boolean hasAnnotation(String annotationName) {
469 ClassFile cf = getClassFile2();
470 AnnotationsAttribute ainfo = (AnnotationsAttribute)
471 cf.getAttribute(AnnotationsAttribute.invisibleTag);
472 AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
473 cf.getAttribute(AnnotationsAttribute.visibleTag);
474 return hasAnnotationType(annotationName, getClassPool(), ainfo, ainfo2);
475 }
476
477
478
479
480 static boolean hasAnnotationType(Class clz, ClassPool cp,
481 AnnotationsAttribute a1,
482 AnnotationsAttribute a2)
483 {
484 return hasAnnotationType(clz.getName(), cp, a1, a2);
485 }
486
487 static boolean hasAnnotationType(String annotationTypeName, ClassPool cp,
488 AnnotationsAttribute a1,
489 AnnotationsAttribute a2)
490 {
491 Annotation[] anno1, anno2;
492
493 if (a1 == null)
494 anno1 = null;
495 else
496 anno1 = a1.getAnnotations();
497
498 if (a2 == null)
499 anno2 = null;
500 else
501 anno2 = a2.getAnnotations();
502
503 if (anno1 != null)
504 for (int i = 0; i < anno1.length; i++)
505 if (anno1[i].getTypeName().equals(annotationTypeName))
506 return true;
507
508 if (anno2 != null)
509 for (int i = 0; i < anno2.length; i++)
510 if (anno2[i].getTypeName().equals(annotationTypeName))
511 return true;
512
513 return false;
514 }
515
516 public Object getAnnotation(Class clz) throws ClassNotFoundException {
517 ClassFile cf = getClassFile2();
518 AnnotationsAttribute ainfo = (AnnotationsAttribute)
519 cf.getAttribute(AnnotationsAttribute.invisibleTag);
520 AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
521 cf.getAttribute(AnnotationsAttribute.visibleTag);
522 return getAnnotationType(clz, getClassPool(), ainfo, ainfo2);
523 }
524
525 static Object getAnnotationType(Class clz, ClassPool cp,
526 AnnotationsAttribute a1, AnnotationsAttribute a2)
527 throws ClassNotFoundException
528 {
529 Annotation[] anno1, anno2;
530
531 if (a1 == null)
532 anno1 = null;
533 else
534 anno1 = a1.getAnnotations();
535
536 if (a2 == null)
537 anno2 = null;
538 else
539 anno2 = a2.getAnnotations();
540
541 String typeName = clz.getName();
542 if (anno1 != null)
543 for (int i = 0; i < anno1.length; i++)
544 if (anno1[i].getTypeName().equals(typeName))
545 return toAnnoType(anno1[i], cp);
546
547 if (anno2 != null)
548 for (int i = 0; i < anno2.length; i++)
549 if (anno2[i].getTypeName().equals(typeName))
550 return toAnnoType(anno2[i], cp);
551
552 return null;
553 }
554
555 public Object[] getAnnotations() throws ClassNotFoundException {
556 return getAnnotations(false);
557 }
558
559 public Object[] getAvailableAnnotations(){
560 try {
561 return getAnnotations(true);
562 }
563 catch (ClassNotFoundException e) {
564 throw new RuntimeException("Unexpected exception ", e);
565 }
566 }
567
568 private Object[] getAnnotations(boolean ignoreNotFound)
569 throws ClassNotFoundException
570 {
571 ClassFile cf = getClassFile2();
572 AnnotationsAttribute ainfo = (AnnotationsAttribute)
573 cf.getAttribute(AnnotationsAttribute.invisibleTag);
574 AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
575 cf.getAttribute(AnnotationsAttribute.visibleTag);
576 return toAnnotationType(ignoreNotFound, getClassPool(), ainfo, ainfo2);
577 }
578
579 static Object[] toAnnotationType(boolean ignoreNotFound, ClassPool cp,
580 AnnotationsAttribute a1, AnnotationsAttribute a2)
581 throws ClassNotFoundException
582 {
583 Annotation[] anno1, anno2;
584 int size1, size2;
585
586 if (a1 == null) {
587 anno1 = null;
588 size1 = 0;
589 }
590 else {
591 anno1 = a1.getAnnotations();
592 size1 = anno1.length;
593 }
594
595 if (a2 == null) {
596 anno2 = null;
597 size2 = 0;
598 }
599 else {
600 anno2 = a2.getAnnotations();
601 size2 = anno2.length;
602 }
603
604 if (!ignoreNotFound){
605 Object[] result = new Object[size1 + size2];
606 for (int i = 0; i < size1; i++)
607 result[i] = toAnnoType(anno1[i], cp);
608
609 for (int j = 0; j < size2; j++)
610 result[j + size1] = toAnnoType(anno2[j], cp);
611
612 return result;
613 }
614 else{
615 ArrayList annotations = new ArrayList();
616 for (int i = 0 ; i < size1 ; i++){
617 try{
618 annotations.add(toAnnoType(anno1[i], cp));
619 }
620 catch(ClassNotFoundException e){}
621 }
622 for (int j = 0; j < size2; j++) {
623 try{
624 annotations.add(toAnnoType(anno2[j], cp));
625 }
626 catch(ClassNotFoundException e){}
627 }
628
629 return annotations.toArray();
630 }
631 }
632
633 static Object[][] toAnnotationType(boolean ignoreNotFound, ClassPool cp,
634 ParameterAnnotationsAttribute a1,
635 ParameterAnnotationsAttribute a2,
636 MethodInfo minfo)
637 throws ClassNotFoundException
638 {
639 int numParameters = 0;
640 if (a1 != null)
641 numParameters = a1.numParameters();
642 else if (a2 != null)
643 numParameters = a2.numParameters();
644 else
645 numParameters = Descriptor.numOfParameters(minfo.getDescriptor());
646
647 Object[][] result = new Object[numParameters][];
648 for (int i = 0; i < numParameters; i++) {
649 Annotation[] anno1, anno2;
650 int size1, size2;
651
652 if (a1 == null) {
653 anno1 = null;
654 size1 = 0;
655 }
656 else {
657 anno1 = a1.getAnnotations()[i];
658 size1 = anno1.length;
659 }
660
661 if (a2 == null) {
662 anno2 = null;
663 size2 = 0;
664 }
665 else {
666 anno2 = a2.getAnnotations()[i];
667 size2 = anno2.length;
668 }
669
670 if (!ignoreNotFound){
671 result[i] = new Object[size1 + size2];
672 for (int j = 0; j < size1; ++j)
673 result[i][j] = toAnnoType(anno1[j], cp);
674
675 for (int j = 0; j < size2; ++j)
676 result[i][j + size1] = toAnnoType(anno2[j], cp);
677 }
678 else{
679 ArrayList annotations = new ArrayList();
680 for (int j = 0 ; j < size1 ; j++){
681 try{
682 annotations.add(toAnnoType(anno1[j], cp));
683 }
684 catch(ClassNotFoundException e){}
685 }
686 for (int j = 0; j < size2; j++){
687 try{
688 annotations.add(toAnnoType(anno2[j], cp));
689 }
690 catch(ClassNotFoundException e){}
691 }
692
693 result[i] = annotations.toArray();
694 }
695 }
696
697 return result;
698 }
699
700 private static Object toAnnoType(Annotation anno, ClassPool cp)
701 throws ClassNotFoundException
702 {
703 try {
704 ClassLoader cl = cp.getClassLoader();
705 return anno.toAnnotationType(cl, cp);
706 }
707 catch (ClassNotFoundException e) {
708 ClassLoader cl2 = cp.getClass().getClassLoader();
709 try {
710 return anno.toAnnotationType(cl2, cp);
711 }
712 catch (ClassNotFoundException e2){
713 try {
714 Class clazz = cp.get(anno.getTypeName()).toClass();
715 return scouter.javassist.bytecode.annotation.AnnotationImpl.make(
716 clazz.getClassLoader(),
717 clazz, cp, anno);
718 }
719 catch (Throwable e3) {
720 throw new ClassNotFoundException(anno.getTypeName());
721 }
722 }
723 }
724 }
725
726 public boolean subclassOf(CtClass superclass) {
727 if (superclass == null)
728 return false;
729
730 String superName = superclass.getName();
731 CtClass curr = this;
732 try {
733 while (curr != null) {
734 if (curr.getName().equals(superName))
735 return true;
736
737 curr = curr.getSuperclass();
738 }
739 }
740 catch (Exception ignored) {}
741 return false;
742 }
743
744 public CtClass getSuperclass() throws NotFoundException {
745 String supername = getClassFile2().getSuperclass();
746 if (supername == null)
747 return null;
748 else
749 return classPool.get(supername);
750 }
751
752 public void setSuperclass(CtClass clazz) throws CannotCompileException {
753 checkModify();
754 if (isInterface())
755 addInterface(clazz);
756 else
757 getClassFile2().setSuperclass(clazz.getName());
758 }
759
760 public CtClass[] getInterfaces() throws NotFoundException {
761 String[] ifs = getClassFile2().getInterfaces();
762 int num = ifs.length;
763 CtClass[] ifc = new CtClass[num];
764 for (int i = 0; i < num; ++i)
765 ifc[i] = classPool.get(ifs[i]);
766
767 return ifc;
768 }
769
770 public void setInterfaces(CtClass[] list) {
771 checkModify();
772 String[] ifs;
773 if (list == null)
774 ifs = new String[0];
775 else {
776 int num = list.length;
777 ifs = new String[num];
778 for (int i = 0; i < num; ++i)
779 ifs[i] = list[i].getName();
780 }
781
782 getClassFile2().setInterfaces(ifs);
783 }
784
785 public void addInterface(CtClass anInterface) {
786 checkModify();
787 if (anInterface != null)
788 getClassFile2().addInterface(anInterface.getName());
789 }
790
791 public CtClass getDeclaringClass() throws NotFoundException {
792 ClassFile cf = getClassFile2();
793 InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
794 InnerClassesAttribute.tag);
795 if (ica == null)
796 return null;
797
798 String name = getName();
799 int n = ica.tableLength();
800 for (int i = 0; i < n; ++i)
801 if (name.equals(ica.innerClass(i))) {
802 String outName = ica.outerClass(i);
803 if (outName != null)
804 return classPool.get(outName);
805 else {
806
807 EnclosingMethodAttribute ema
808 = (EnclosingMethodAttribute)cf.getAttribute(
809 EnclosingMethodAttribute.tag);
810 if (ema != null)
811 return classPool.get(ema.className());
812 }
813 }
814
815 return null;
816 }
817
818 public CtBehavior getEnclosingBehavior() throws NotFoundException {
819 ClassFile cf = getClassFile2();
820 EnclosingMethodAttribute ema
821 = (EnclosingMethodAttribute)cf.getAttribute(
822 EnclosingMethodAttribute.tag);
823 if (ema == null)
824 return null;
825 else {
826 CtClass enc = classPool.get(ema.className());
827 String name = ema.methodName();
828 if (MethodInfo.nameInit.equals(name))
829 return enc.getConstructor(ema.methodDescriptor());
830 else if(MethodInfo.nameClinit.equals(name))
831 return enc.getClassInitializer();
832 else
833 return enc.getMethod(name, ema.methodDescriptor());
834 }
835 }
836
837 public CtClass makeNestedClass(String name, boolean isStatic) {
838 if (!isStatic)
839 throw new RuntimeException(
840 "sorry, only nested static class is supported");
841
842 checkModify();
843 CtClass c = classPool.makeNestedClass(getName() + "$" + name);
844 ClassFile cf = getClassFile2();
845 ClassFile cf2 = c.getClassFile2();
846 InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
847 InnerClassesAttribute.tag);
848 if (ica == null) {
849 ica = new InnerClassesAttribute(cf.getConstPool());
850 cf.addAttribute(ica);
851 }
852
853 ica.append(c.getName(), this.getName(), name,
854 (cf2.getAccessFlags() & ~AccessFlag.SUPER) | AccessFlag.STATIC);
855 cf2.addAttribute(ica.copy(cf2.getConstPool(), null));
856 return c;
857 }
858
859
860
861 private void nameReplaced() {
862 CtMember.Cache cache = hasMemberCache();
863 if (cache != null) {
864 CtMember mth = cache.methodHead();
865 CtMember tail = cache.lastMethod();
866 while (mth != tail) {
867 mth = mth.next();
868 mth.nameReplaced();
869 }
870 }
871 }
872
873
874
875
876 protected CtMember.Cache hasMemberCache() {
877 if (memberCache != null)
878 return (CtMember.Cache)memberCache.get();
879 else
880 return null;
881 }
882
883 protected synchronized CtMember.Cache getMembers() {
884 CtMember.Cache cache = null;
885 if (memberCache == null
886 || (cache = (CtMember.Cache)memberCache.get()) == null) {
887 cache = new CtMember.Cache(this);
888 makeFieldCache(cache);
889 makeBehaviorCache(cache);
890 memberCache = new WeakReference(cache);
891 }
892
893 return cache;
894 }
895
896 private void makeFieldCache(CtMember.Cache cache) {
897 List list = getClassFile2().getFields();
898 int n = list.size();
899 for (int i = 0; i < n; ++i) {
900 FieldInfo finfo = (FieldInfo)list.get(i);
901 CtField newField = new CtField(finfo, this);
902 cache.addField(newField);
903 }
904 }
905
906 private void makeBehaviorCache(CtMember.Cache cache) {
907 List list = getClassFile2().getMethods();
908 int n = list.size();
909 for (int i = 0; i < n; ++i) {
910 MethodInfo minfo = (MethodInfo)list.get(i);
911 if (minfo.isMethod()) {
912 CtMethod newMethod = new CtMethod(minfo, this);
913 cache.addMethod(newMethod);
914 }
915 else {
916 CtConstructor newCons = new CtConstructor(minfo, this);
917 cache.addConstructor(newCons);
918 }
919 }
920 }
921
922 public CtField[] getFields() {
923 ArrayList alist = new ArrayList();
924 getFields(alist, this);
925 return (CtField[])alist.toArray(new CtField[alist.size()]);
926 }
927
928 private static void getFields(ArrayList alist, CtClass cc) {
929 int i, num;
930 if (cc == null)
931 return;
932
933 try {
934 getFields(alist, cc.getSuperclass());
935 }
936 catch (NotFoundException e) {}
937
938 try {
939 CtClass[] ifs = cc.getInterfaces();
940 num = ifs.length;
941 for (i = 0; i < num; ++i)
942 getFields(alist, ifs[i]);
943 }
944 catch (NotFoundException e) {}
945
946 CtMember.Cache memCache = ((CtClassType)cc).getMembers();
947 CtMember field = memCache.fieldHead();
948 CtMember tail = memCache.lastField();
949 while (field != tail) {
950 field = field.next();
951 if (!Modifier.isPrivate(field.getModifiers()))
952 alist.add(field);
953 }
954 }
955
956 public CtField getField(String name, String desc) throws NotFoundException {
957 CtField f = getField2(name, desc);
958 return checkGetField(f, name, desc);
959 }
960
961 private CtField checkGetField(CtField f, String name, String desc)
962 throws NotFoundException
963 {
964 if (f == null) {
965 String msg = "field: " + name;
966 if (desc != null)
967 msg += " type " + desc;
968
969 throw new NotFoundException(msg + " in " + getName());
970 }
971 else
972 return f;
973 }
974
975 CtField getField2(String name, String desc) {
976 CtField df = getDeclaredField2(name, desc);
977 if (df != null)
978 return df;
979
980 try {
981 CtClass[] ifs = getInterfaces();
982 int num = ifs.length;
983 for (int i = 0; i < num; ++i) {
984 CtField f = ifs[i].getField2(name, desc);
985 if (f != null)
986 return f;
987 }
988
989 CtClass s = getSuperclass();
990 if (s != null)
991 return s.getField2(name, desc);
992 }
993 catch (NotFoundException e) {}
994 return null;
995 }
996
997 public CtField[] getDeclaredFields() {
998 CtMember.Cache memCache = getMembers();
999 CtMember field = memCache.fieldHead();
1000 CtMember tail = memCache.lastField();
1001 int num = CtMember.Cache.count(field, tail);
1002 CtField[] cfs = new CtField[num];
1003 int i = 0;
1004 while (field != tail) {
1005 field = field.next();
1006 cfs[i++] = (CtField)field;
1007 }
1008
1009 return cfs;
1010 }
1011
1012 public CtField getDeclaredField(String name) throws NotFoundException {
1013 return getDeclaredField(name, null);
1014 }
1015
1016 public CtField getDeclaredField(String name, String desc) throws NotFoundException {
1017 CtField f = getDeclaredField2(name, desc);
1018 return checkGetField(f, name, desc);
1019 }
1020
1021 private CtField getDeclaredField2(String name, String desc) {
1022 CtMember.Cache memCache = getMembers();
1023 CtMember field = memCache.fieldHead();
1024 CtMember tail = memCache.lastField();
1025 while (field != tail) {
1026 field = field.next();
1027 if (field.getName().equals(name)
1028 && (desc == null || desc.equals(field.getSignature())))
1029 return (CtField)field;
1030 }
1031
1032 return null;
1033 }
1034
1035 public CtBehavior[] getDeclaredBehaviors() {
1036 CtMember.Cache memCache = getMembers();
1037 CtMember cons = memCache.consHead();
1038 CtMember consTail = memCache.lastCons();
1039 int cnum = CtMember.Cache.count(cons, consTail);
1040 CtMember mth = memCache.methodHead();
1041 CtMember mthTail = memCache.lastMethod();
1042 int mnum = CtMember.Cache.count(mth, mthTail);
1043
1044 CtBehavior[] cb = new CtBehavior[cnum + mnum];
1045 int i = 0;
1046 while (cons != consTail) {
1047 cons = cons.next();
1048 cb[i++] = (CtBehavior)cons;
1049 }
1050
1051 while (mth != mthTail) {
1052 mth = mth.next();
1053 cb[i++] = (CtBehavior)mth;
1054 }
1055
1056 return cb;
1057 }
1058
1059 public CtConstructor[] getConstructors() {
1060 CtMember.Cache memCache = getMembers();
1061 CtMember cons = memCache.consHead();
1062 CtMember consTail = memCache.lastCons();
1063
1064 int n = 0;
1065 CtMember mem = cons;
1066 while (mem != consTail) {
1067 mem = mem.next();
1068 if (isPubCons((CtConstructor)mem))
1069 n++;
1070 }
1071
1072 CtConstructor[] result = new CtConstructor[n];
1073 int i = 0;
1074 mem = cons;
1075 while (mem != consTail) {
1076 mem = mem.next();
1077 CtConstructor cc = (CtConstructor)mem;
1078 if (isPubCons(cc))
1079 result[i++] = cc;
1080 }
1081
1082 return result;
1083 }
1084
1085 private static boolean isPubCons(CtConstructor cons) {
1086 return !Modifier.isPrivate(cons.getModifiers())
1087 && cons.isConstructor();
1088 }
1089
1090 public CtConstructor getConstructor(String desc)
1091 throws NotFoundException
1092 {
1093 CtMember.Cache memCache = getMembers();
1094 CtMember cons = memCache.consHead();
1095 CtMember consTail = memCache.lastCons();
1096
1097 while (cons != consTail) {
1098 cons = cons.next();
1099 CtConstructor cc = (CtConstructor)cons;
1100 if (cc.getMethodInfo2().getDescriptor().equals(desc)
1101 && cc.isConstructor())
1102 return cc;
1103 }
1104
1105 return super.getConstructor(desc);
1106 }
1107
1108 public CtConstructor[] getDeclaredConstructors() {
1109 CtMember.Cache memCache = getMembers();
1110 CtMember cons = memCache.consHead();
1111 CtMember consTail = memCache.lastCons();
1112
1113 int n = 0;
1114 CtMember mem = cons;
1115 while (mem != consTail) {
1116 mem = mem.next();
1117 CtConstructor cc = (CtConstructor)mem;
1118 if (cc.isConstructor())
1119 n++;
1120 }
1121
1122 CtConstructor[] result = new CtConstructor[n];
1123 int i = 0;
1124 mem = cons;
1125 while (mem != consTail) {
1126 mem = mem.next();
1127 CtConstructor cc = (CtConstructor)mem;
1128 if (cc.isConstructor())
1129 result[i++] = cc;
1130 }
1131
1132 return result;
1133 }
1134
1135 public CtConstructor getClassInitializer() {
1136 CtMember.Cache memCache = getMembers();
1137 CtMember cons = memCache.consHead();
1138 CtMember consTail = memCache.lastCons();
1139
1140 while (cons != consTail) {
1141 cons = cons.next();
1142 CtConstructor cc = (CtConstructor)cons;
1143 if (cc.isClassInitializer())
1144 return cc;
1145 }
1146
1147 return null;
1148 }
1149
1150 public CtMethod[] getMethods() {
1151 HashMap h = new HashMap();
1152 getMethods0(h, this);
1153 return (CtMethod[])h.values().toArray(new CtMethod[h.size()]);
1154 }
1155
1156 private static void getMethods0(HashMap h, CtClass cc) {
1157 try {
1158 CtClass[] ifs = cc.getInterfaces();
1159 int size = ifs.length;
1160 for (int i = 0; i < size; ++i)
1161 getMethods0(h, ifs[i]);
1162 }
1163 catch (NotFoundException e) {}
1164
1165 try {
1166 CtClass s = cc.getSuperclass();
1167 if (s != null)
1168 getMethods0(h, s);
1169 }
1170 catch (NotFoundException e) {}
1171
1172 if (cc instanceof CtClassType) {
1173 CtMember.Cache memCache = ((CtClassType)cc).getMembers();
1174 CtMember mth = memCache.methodHead();
1175 CtMember mthTail = memCache.lastMethod();
1176
1177 while (mth != mthTail) {
1178 mth = mth.next();
1179 if (!Modifier.isPrivate(mth.getModifiers()))
1180 h.put(((CtMethod)mth).getStringRep(), mth);
1181 }
1182 }
1183 }
1184
1185 public CtMethod getMethod(String name, String desc)
1186 throws NotFoundException
1187 {
1188 CtMethod m = getMethod0(this, name, desc);
1189 if (m != null)
1190 return m;
1191 else
1192 throw new NotFoundException(name + "(..) is not found in "
1193 + getName());
1194 }
1195
1196 private static CtMethod getMethod0(CtClass cc,
1197 String name, String desc) {
1198 if (cc instanceof CtClassType) {
1199 CtMember.Cache memCache = ((CtClassType)cc).getMembers();
1200 CtMember mth = memCache.methodHead();
1201 CtMember mthTail = memCache.lastMethod();
1202
1203 while (mth != mthTail) {
1204 mth = mth.next();
1205 if (mth.getName().equals(name)
1206 && ((CtMethod)mth).getMethodInfo2().getDescriptor().equals(desc))
1207 return (CtMethod)mth;
1208 }
1209 }
1210
1211 try {
1212 CtClass s = cc.getSuperclass();
1213 if (s != null) {
1214 CtMethod m = getMethod0(s, name, desc);
1215 if (m != null)
1216 return m;
1217 }
1218 }
1219 catch (NotFoundException e) {}
1220
1221 try {
1222 CtClass[] ifs = cc.getInterfaces();
1223 int size = ifs.length;
1224 for (int i = 0; i < size; ++i) {
1225 CtMethod m = getMethod0(ifs[i], name, desc);
1226 if (m != null)
1227 return m;
1228 }
1229 }
1230 catch (NotFoundException e) {}
1231 return null;
1232 }
1233
1234 public CtMethod[] getDeclaredMethods() {
1235 CtMember.Cache memCache = getMembers();
1236 CtMember mth = memCache.methodHead();
1237 CtMember mthTail = memCache.lastMethod();
1238 int num = CtMember.Cache.count(mth, mthTail);
1239 CtMethod[] cms = new CtMethod[num];
1240 int i = 0;
1241 while (mth != mthTail) {
1242 mth = mth.next();
1243 cms[i++] = (CtMethod)mth;
1244 }
1245
1246 return cms;
1247 }
1248
1249 public CtMethod[] getDeclaredMethods(String name) throws NotFoundException {
1250 CtMember.Cache memCache = getMembers();
1251 CtMember mth = memCache.methodHead();
1252 CtMember mthTail = memCache.lastMethod();
1253 ArrayList methods = new ArrayList();
1254 while (mth != mthTail) {
1255 mth = mth.next();
1256 if (mth.getName().equals(name))
1257 methods.add((CtMethod)mth);
1258 }
1259
1260 return (CtMethod[]) methods.toArray(new CtMethod[methods.size()]);
1261 }
1262
1263 public CtMethod getDeclaredMethod(String name) throws NotFoundException {
1264 CtMember.Cache memCache = getMembers();
1265 CtMember mth = memCache.methodHead();
1266 CtMember mthTail = memCache.lastMethod();
1267 while (mth != mthTail) {
1268 mth = mth.next();
1269 if (mth.getName().equals(name))
1270 return (CtMethod)mth;
1271 }
1272
1273 throw new NotFoundException(name + "(..) is not found in "
1274 + getName());
1275 }
1276
1277 public CtMethod getDeclaredMethod(String name, CtClass[] params)
1278 throws NotFoundException
1279 {
1280 String desc = Descriptor.ofParameters(params);
1281 CtMember.Cache memCache = getMembers();
1282 CtMember mth = memCache.methodHead();
1283 CtMember mthTail = memCache.lastMethod();
1284
1285 while (mth != mthTail) {
1286 mth = mth.next();
1287 if (mth.getName().equals(name)
1288 && ((CtMethod)mth).getMethodInfo2().getDescriptor().startsWith(desc))
1289 return (CtMethod)mth;
1290 }
1291
1292 throw new NotFoundException(name + "(..) is not found in "
1293 + getName());
1294 }
1295
1296 public void addField(CtField f, String init)
1297 throws CannotCompileException
1298 {
1299 addField(f, CtField.Initializer.byExpr(init));
1300 }
1301
1302 public void addField(CtField f, CtField.Initializer init)
1303 throws CannotCompileException
1304 {
1305 checkModify();
1306 if (f.getDeclaringClass() != this)
1307 throw new CannotCompileException("cannot add");
1308
1309 if (init == null)
1310 init = f.getInit();
1311
1312 if (init != null) {
1313 init.check(f.getSignature());
1314 int mod = f.getModifiers();
1315 if (Modifier.isStatic(mod) && Modifier.isFinal(mod))
1316 try {
1317 ConstPool cp = getClassFile2().getConstPool();
1318 int index = init.getConstantValue(cp, f.getType());
1319 if (index != 0) {
1320 f.getFieldInfo2().addAttribute(new ConstantAttribute(cp, index));
1321 init = null;
1322 }
1323 }
1324 catch (NotFoundException e) {}
1325 }
1326
1327 getMembers().addField(f);
1328 getClassFile2().addField(f.getFieldInfo2());
1329
1330 if (init != null) {
1331 FieldInitLink fil = new FieldInitLink(f, init);
1332 FieldInitLink link = fieldInitializers;
1333 if (link == null)
1334 fieldInitializers = fil;
1335 else {
1336 while (link.next != null)
1337 link = link.next;
1338
1339 link.next = fil;
1340 }
1341 }
1342 }
1343
1344 public void removeField(CtField f) throws NotFoundException {
1345 checkModify();
1346 FieldInfo fi = f.getFieldInfo2();
1347 ClassFile cf = getClassFile2();
1348 if (cf.getFields().remove(fi)) {
1349 getMembers().remove(f);
1350 gcConstPool = true;
1351 }
1352 else
1353 throw new NotFoundException(f.toString());
1354 }
1355
1356 public CtConstructor makeClassInitializer()
1357 throws CannotCompileException
1358 {
1359 CtConstructor clinit = getClassInitializer();
1360 if (clinit != null)
1361 return clinit;
1362
1363 checkModify();
1364 ClassFile cf = getClassFile2();
1365 Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
1366 modifyClassConstructor(cf, code, 0, 0);
1367 return getClassInitializer();
1368 }
1369
1370 public void addConstructor(CtConstructor c)
1371 throws CannotCompileException
1372 {
1373 checkModify();
1374 if (c.getDeclaringClass() != this)
1375 throw new CannotCompileException("cannot add");
1376
1377 getMembers().addConstructor(c);
1378 getClassFile2().addMethod(c.getMethodInfo2());
1379 }
1380
1381 public void removeConstructor(CtConstructor m) throws NotFoundException {
1382 checkModify();
1383 MethodInfo mi = m.getMethodInfo2();
1384 ClassFile cf = getClassFile2();
1385 if (cf.getMethods().remove(mi)) {
1386 getMembers().remove(m);
1387 gcConstPool = true;
1388 }
1389 else
1390 throw new NotFoundException(m.toString());
1391 }
1392
1393 public void addMethod(CtMethod m) throws CannotCompileException {
1394 checkModify();
1395 if (m.getDeclaringClass() != this)
1396 throw new CannotCompileException("bad declaring class");
1397
1398 int mod = m.getModifiers();
1399 if ((getModifiers() & Modifier.INTERFACE) != 0) {
1400 m.setModifiers(mod | Modifier.PUBLIC);
1401 if ((mod & Modifier.ABSTRACT) == 0)
1402 throw new CannotCompileException(
1403 "an interface method must be abstract: " + m.toString());
1404 }
1405
1406 getMembers().addMethod(m);
1407 getClassFile2().addMethod(m.getMethodInfo2());
1408 if ((mod & Modifier.ABSTRACT) != 0)
1409 setModifiers(getModifiers() | Modifier.ABSTRACT);
1410 }
1411
1412 public void removeMethod(CtMethod m) throws NotFoundException {
1413 checkModify();
1414 MethodInfo mi = m.getMethodInfo2();
1415 ClassFile cf = getClassFile2();
1416 if (cf.getMethods().remove(mi)) {
1417 getMembers().remove(m);
1418 gcConstPool = true;
1419 }
1420 else
1421 throw new NotFoundException(m.toString());
1422 }
1423
1424 public byte[] getAttribute(String name) {
1425 AttributeInfo ai = getClassFile2().getAttribute(name);
1426 if (ai == null)
1427 return null;
1428 else
1429 return ai.get();
1430 }
1431
1432 public void setAttribute(String name, byte[] data) {
1433 checkModify();
1434 ClassFile cf = getClassFile2();
1435 cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data));
1436 }
1437
1438 public void instrument(CodeConverter converter)
1439 throws CannotCompileException
1440 {
1441 checkModify();
1442 ClassFile cf = getClassFile2();
1443 ConstPool cp = cf.getConstPool();
1444 List list = cf.getMethods();
1445 int n = list.size();
1446 for (int i = 0; i < n; ++i) {
1447 MethodInfo minfo = (MethodInfo)list.get(i);
1448 converter.doit(this, minfo, cp);
1449 }
1450 }
1451
1452 public void instrument(ExprEditor editor)
1453 throws CannotCompileException
1454 {
1455 checkModify();
1456 ClassFile cf = getClassFile2();
1457 List list = cf.getMethods();
1458 int n = list.size();
1459 for (int i = 0; i < n; ++i) {
1460 MethodInfo minfo = (MethodInfo)list.get(i);
1461 editor.doit(this, minfo);
1462 }
1463 }
1464
1465
1466
1467
1468
1469 public void prune() {
1470 if (wasPruned)
1471 return;
1472
1473 wasPruned = wasFrozen = true;
1474 getClassFile2().prune();
1475 }
1476
1477 public void rebuildClassFile() { gcConstPool = true; }
1478
1479 public void toBytecode(DataOutputStream out)
1480 throws CannotCompileException, IOException
1481 {
1482 try {
1483 if (isModified()) {
1484 checkPruned("toBytecode");
1485 ClassFile cf = getClassFile2();
1486 if (gcConstPool) {
1487 cf.compact();
1488 gcConstPool = false;
1489 }
1490
1491 modifyClassConstructor(cf);
1492 modifyConstructors(cf);
1493 if (debugDump != null)
1494 dumpClassFile(cf);
1495
1496 cf.write(out);
1497 out.flush();
1498 fieldInitializers = null;
1499 if (doPruning) {
1500
1501 cf.prune();
1502 wasPruned = true;
1503 }
1504 }
1505 else {
1506 classPool.writeClassfile(getName(), out);
1507
1508
1509 }
1510
1511 getCount = 0;
1512 wasFrozen = true;
1513 }
1514 catch (NotFoundException e) {
1515 throw new CannotCompileException(e);
1516 }
1517 catch (IOException e) {
1518 throw new CannotCompileException(e);
1519 }
1520 }
1521
1522 private void dumpClassFile(ClassFile cf) throws IOException {
1523 DataOutputStream dump = makeFileOutput(debugDump);
1524 try {
1525 cf.write(dump);
1526 }
1527 finally {
1528 dump.close();
1529 }
1530 }
1531
1532
1533
1534 private void checkPruned(String method) {
1535 if (wasPruned)
1536 throw new RuntimeException(method + "(): " + getName()
1537 + " was pruned.");
1538 }
1539
1540 public boolean stopPruning(boolean stop) {
1541 boolean prev = !doPruning;
1542 doPruning = !stop;
1543 return prev;
1544 }
1545
1546 private void modifyClassConstructor(ClassFile cf)
1547 throws CannotCompileException, NotFoundException
1548 {
1549 if (fieldInitializers == null)
1550 return;
1551
1552 Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
1553 Javac jv = new Javac(code, this);
1554 int stacksize = 0;
1555 boolean doInit = false;
1556 for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
1557 CtField f = fi.field;
1558 if (Modifier.isStatic(f.getModifiers())) {
1559 doInit = true;
1560 int s = fi.init.compileIfStatic(f.getType(), f.getName(),
1561 code, jv);
1562 if (stacksize < s)
1563 stacksize = s;
1564 }
1565 }
1566
1567 if (doInit)
1568 modifyClassConstructor(cf, code, stacksize, 0);
1569 }
1570
1571 private void modifyClassConstructor(ClassFile cf, Bytecode code,
1572 int stacksize, int localsize)
1573 throws CannotCompileException
1574 {
1575 MethodInfo m = cf.getStaticInitializer();
1576 if (m == null) {
1577 code.add(Bytecode.RETURN);
1578 code.setMaxStack(stacksize);
1579 code.setMaxLocals(localsize);
1580 m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V");
1581 m.setAccessFlags(AccessFlag.STATIC);
1582 m.setCodeAttribute(code.toCodeAttribute());
1583 cf.addMethod(m);
1584 CtMember.Cache cache = hasMemberCache();
1585 if (cache != null)
1586 cache.addConstructor(new CtConstructor(m, this));
1587 }
1588 else {
1589 CodeAttribute codeAttr = m.getCodeAttribute();
1590 if (codeAttr == null)
1591 throw new CannotCompileException("empty <clinit>");
1592
1593 try {
1594 CodeIterator it = codeAttr.iterator();
1595 int pos = it.insertEx(code.get());
1596 it.insert(code.getExceptionTable(), pos);
1597 int maxstack = codeAttr.getMaxStack();
1598 if (maxstack < stacksize)
1599 codeAttr.setMaxStack(stacksize);
1600
1601 int maxlocals = codeAttr.getMaxLocals();
1602 if (maxlocals < localsize)
1603 codeAttr.setMaxLocals(localsize);
1604 }
1605 catch (BadBytecode e) {
1606 throw new CannotCompileException(e);
1607 }
1608 }
1609
1610 try {
1611 m.rebuildStackMapIf6(classPool, cf);
1612 }
1613 catch (BadBytecode e) {
1614 throw new CannotCompileException(e);
1615 }
1616 }
1617
1618 private void modifyConstructors(ClassFile cf)
1619 throws CannotCompileException, NotFoundException
1620 {
1621 if (fieldInitializers == null)
1622 return;
1623
1624 ConstPool cp = cf.getConstPool();
1625 List list = cf.getMethods();
1626 int n = list.size();
1627 for (int i = 0; i < n; ++i) {
1628 MethodInfo minfo = (MethodInfo)list.get(i);
1629 if (minfo.isConstructor()) {
1630 CodeAttribute codeAttr = minfo.getCodeAttribute();
1631 if (codeAttr != null)
1632 try {
1633 Bytecode init = new Bytecode(cp, 0,
1634 codeAttr.getMaxLocals());
1635 CtClass[] params
1636 = Descriptor.getParameterTypes(
1637 minfo.getDescriptor(),
1638 classPool);
1639 int stacksize = makeFieldInitializer(init, params);
1640 insertAuxInitializer(codeAttr, init, stacksize);
1641 minfo.rebuildStackMapIf6(classPool, cf);
1642 }
1643 catch (BadBytecode e) {
1644 throw new CannotCompileException(e);
1645 }
1646 }
1647 }
1648 }
1649
1650 private static void insertAuxInitializer(CodeAttribute codeAttr,
1651 Bytecode initializer,
1652 int stacksize)
1653 throws BadBytecode
1654 {
1655 CodeIterator it = codeAttr.iterator();
1656 int index = it.skipSuperConstructor();
1657 if (index < 0) {
1658 index = it.skipThisConstructor();
1659 if (index >= 0)
1660 return;
1661
1662
1663 }
1664
1665 int pos = it.insertEx(initializer.get());
1666 it.insert(initializer.getExceptionTable(), pos);
1667 int maxstack = codeAttr.getMaxStack();
1668 if (maxstack < stacksize)
1669 codeAttr.setMaxStack(stacksize);
1670 }
1671
1672 private int makeFieldInitializer(Bytecode code, CtClass[] parameters)
1673 throws CannotCompileException, NotFoundException
1674 {
1675 int stacksize = 0;
1676 Javac jv = new Javac(code, this);
1677 try {
1678 jv.recordParams(parameters, false);
1679 }
1680 catch (CompileError e) {
1681 throw new CannotCompileException(e);
1682 }
1683
1684 for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
1685 CtField f = fi.field;
1686 if (!Modifier.isStatic(f.getModifiers())) {
1687 int s = fi.init.compile(f.getType(), f.getName(), code,
1688 parameters, jv);
1689 if (stacksize < s)
1690 stacksize = s;
1691 }
1692 }
1693
1694 return stacksize;
1695 }
1696
1697
1698
1699 Hashtable getHiddenMethods() {
1700 if (hiddenMethods == null)
1701 hiddenMethods = new Hashtable();
1702
1703 return hiddenMethods;
1704 }
1705
1706 int getUniqueNumber() { return uniqueNumberSeed++; }
1707
1708 public String makeUniqueName(String prefix) {
1709 HashMap table = new HashMap();
1710 makeMemberList(table);
1711 Set keys = table.keySet();
1712 String[] methods = new String[keys.size()];
1713 keys.toArray(methods);
1714
1715 if (notFindInArray(prefix, methods))
1716 return prefix;
1717
1718 int i = 100;
1719 String name;
1720 do {
1721 if (i > 999)
1722 throw new RuntimeException("too many unique name");
1723
1724 name = prefix + i++;
1725 } while (!notFindInArray(name, methods));
1726 return name;
1727 }
1728
1729 private static boolean notFindInArray(String prefix, String[] values) {
1730 int len = values.length;
1731 for (int i = 0; i < len; i++)
1732 if (values[i].startsWith(prefix))
1733 return false;
1734
1735 return true;
1736 }
1737
1738 private void makeMemberList(HashMap table) {
1739 int mod = getModifiers();
1740 if (Modifier.isAbstract(mod) || Modifier.isInterface(mod))
1741 try {
1742 CtClass[] ifs = getInterfaces();
1743 int size = ifs.length;
1744 for (int i = 0; i < size; i++) {
1745 CtClass ic =ifs[i];
1746 if (ic != null && ic instanceof CtClassType)
1747 ((CtClassType)ic).makeMemberList(table);
1748 }
1749 }
1750 catch (NotFoundException e) {}
1751
1752 try {
1753 CtClass s = getSuperclass();
1754 if (s != null && s instanceof CtClassType)
1755 ((CtClassType)s).makeMemberList(table);
1756 }
1757 catch (NotFoundException e) {}
1758
1759 List list = getClassFile2().getMethods();
1760 int n = list.size();
1761 for (int i = 0; i < n; i++) {
1762 MethodInfo minfo = (MethodInfo)list.get(i);
1763 table.put(minfo.getName(), this);
1764 }
1765
1766 list = getClassFile2().getFields();
1767 n = list.size();
1768 for (int i = 0; i < n; i++) {
1769 FieldInfo finfo = (FieldInfo)list.get(i);
1770 table.put(finfo.getName(), this);
1771 }
1772 }
1773 }
1774
1775 class FieldInitLink {
1776 FieldInitLink next;
1777 CtField field;
1778 CtField.Initializer init;
1779
1780 FieldInitLink(CtField f, CtField.Initializer i) {
1781 next = null;
1782 field = f;
1783 init = i;
1784 }
1785 }